package com.youlin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.youlin.dto.*;
import com.youlin.dto.req.EditCustomReqDto;
import com.youlin.dto.res.CMListResDto;
import com.youlin.dto.res.CustomResDto;
import com.youlin.entities.BygAppointment;
import com.youlin.entities.BygCustom;
import com.youlin.entities.BygCustomData;
import com.youlin.entities.BygFarewellHall;
import com.youlin.mapper.BygCustomMapper;
import com.youlin.service.BygAppointmentService;
import com.youlin.service.BygCustomDataService;
import com.youlin.service.BygCustomService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlin.service.BygFarewellHallService;
import com.youlin.untils.BaseService;
import com.youlin.untils.MyEnum;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
public class BygCustomServiceImpl extends ServiceImpl<BygCustomMapper, BygCustom> implements BygCustomService {

    @Autowired
    private BygAppointmentService bygAppointmentService;
    @Autowired
    private BygFarewellHallService bygFarewellHallService;
    @Autowired
    private BygCustomDataService bygCustomDataService;

    @Override
    public PageDataResDto<List<CMListResDto>> findAllCustoms(Integer unitId, PageInfo pageInfo) {
        QueryWrapper<BygCustom> queryWrapper = new QueryWrapper<BygCustom>()
                .eq("unit_id", unitId).orderByDesc("no");
        IPage<BygCustom> page = page(new Page<>(pageInfo.getPage(), pageInfo.getSize()), queryWrapper);
        List<CMListResDto> cmListResDtos = Lists.newArrayList();
        if (page.getTotal() > 0) {
            cmListResDtos = page.getRecords().parallelStream().map(c ->
                    BaseService.copyProperties(c, CMListResDto.class)).collect(Collectors.toList());
            if (pageInfo.getPage() == 1) cmListResDtos.get(0).setPageType(0);
            if ((pageInfo.getPage() - 1) * pageInfo.getSize() + cmListResDtos.size() == page.getTotal())
                cmListResDtos.get(cmListResDtos.size() - 1).setPageType(1);
            List<Integer> cIds = cmListResDtos.parallelStream().map(CMListResDto::getId).collect(Collectors.toList());
            LambdaQueryWrapper<BygCustomData> wrapper = Wrappers.lambdaQuery(BygCustomData.class)
                    .in(BygCustomData::getCId, cIds).eq(BygCustomData::getNo, 0);
            Map<String, String> cdUrlMap = bygCustomDataService.list(wrapper).parallelStream()
                    .collect(Collectors.toMap(cd -> cd.getCId() + "-" + cd.getType(), BygCustomData::getUrl));
            cmListResDtos.parallelStream().forEach(c -> {
                String coverUrl = cdUrlMap.get(c.getId() + "-" + MyEnum.CUSTOM_DATA_COVER.getValue());
                if (StringUtils.isNotBlank(coverUrl)) c.setCoverUrl(coverUrl);
                else {
                    coverUrl = cdUrlMap.get(c.getId() + "-" + MyEnum.CUSTOM_DATA_PIC.getValue());
                    if (StringUtils.isNotBlank(coverUrl)) c.setCoverUrl(coverUrl);
                }
            });
        }
        return new PageDataResDto<List<CMListResDto>>(Status.SUCCESS)
                .setData(cmListResDtos).setPageInfo(pageInfo.setTotal(page.getTotal()));
    }

    @Override
    public PageDataResDto<List<CMListResDto>> findAllCustoms(String amUuId, PageInfo pageInfo) {
        BygAppointment appointment = bygAppointmentService.findAppointmentByUuId(amUuId);
        if (appointment == null) return new PageDataResDto(Status.PARAMETERERROR);
        BygFarewellHall farewellHall = bygFarewellHallService.getById(appointment.getFhId());
        return findAllCustoms(farewellHall.getUnitId(), pageInfo);
    }

    @Override
    public BaseDataResDto<CustomResDto> findCustomById(Integer customId) {
        BygCustom custom = getById(customId);
        if (custom == null) return new BaseDataResDto<>(Status.PARAMETERERROR);
        CustomResDto customResDto = new CustomResDto();
        BeanUtils.copyProperties(custom, customResDto);
        List<BygCustomData> customDatas = bygCustomDataService.list(
                new QueryWrapper<BygCustomData>().eq("c_id", customId));
        List<String> pictureUrls = customDatas.parallelStream()
                .filter(cd -> cd.getType() == MyEnum.CUSTOM_DATA_PIC.getValue())
                .sorted(Comparator.comparingInt(BygCustomData::getNo))
                .map(BygCustomData::getUrl).collect(Collectors.toList());
        if (pictureUrls.size() > 0) customResDto.setPictureUrls(pictureUrls);
        Optional<BygCustomData> videoCoverOptional = customDatas.parallelStream()
                .filter(cd -> cd.getType() == MyEnum.CUSTOM_DATA_COVER.getValue()).findFirst();
        if (videoCoverOptional.isPresent()) customResDto.setVideoCoverUrl(videoCoverOptional.get().getUrl());
        Optional<BygCustomData> videoOptional = customDatas.parallelStream()
                .filter(cd -> cd.getType() == MyEnum.CUSTOM_DATA_VIDEO.getValue()).findFirst();
        if (videoOptional.isPresent()) customResDto.setVideoUrl(videoOptional.get().getUrl());
        return new BaseDataResDto<CustomResDto>(Status.SUCCESS).setData(customResDto);
    }

    @Override
    @Transactional
    public BaseResDto editCustom(Integer unitId, EditCustomReqDto data) {
        LambdaQueryWrapper<BygCustom> wrapper = Wrappers.lambdaQuery(BygCustom.class)
                .eq(BygCustom::getUnitId, unitId);
        List<BygCustom> bygCustoms = list(wrapper);
        boolean anyMatch = bygCustoms.parallelStream()
                .anyMatch(c -> c.getId() != data.getCustomId() && data.getName().equals(c.getName()));
        if (anyMatch) return new BaseResDto(Status.CNDUPLICATE);
        BygCustom bygCustom = new BygCustom().setName(data.getName()).setContent(data.getContent());
        if (data.getCustomId() == null) { // 新建风俗信息数据
            Optional<BygCustom> optional = bygCustoms.parallelStream().max(Comparator.comparingInt(BygCustom::getNo));
            Integer no = optional.isPresent() ? optional.get().getNo()+1 : 0;
            bygCustom.setUnitId(unitId).setCreateTime(LocalDateTime.now()).setNo(no);
            if (! save(bygCustom)) return new BaseResDto<>(Status.ERROR, "保存风俗信息主体失败");
        } else { // 编辑风俗信息数据
            bygCustom.setId(data.getCustomId()).setUpdateTime(LocalDateTime.now());
            if (! updateById(bygCustom)) return new BaseResDto<>(Status.ERROR, "修改风俗信息主体失败");
            if (! bygCustomDataService.remove(new QueryWrapper<BygCustomData>().eq("c_id", data.getCustomId())))
                return new BaseResDto(Status.ERROR, "删除风俗信息原资料失败");
        }
        List<BygCustomData> customDatas = Lists.newArrayList();
        if (data.getPictureUrls() != null && data.getPictureUrls().size() > 0) {
            AtomicInteger atomicInteger = new AtomicInteger(0);
            customDatas.addAll(data.getPictureUrls().stream().map(pu -> new BygCustomData()
                    .setCId(bygCustom.getId()).setNo(atomicInteger.getAndIncrement())
                    .setType(MyEnum.CUSTOM_DATA_PIC.getValue()).setUrl(pu)).collect(Collectors.toList()));
        }
        if (StringUtils.isNotBlank(data.getVideoCoverUrl()))
            customDatas.add(new BygCustomData().setCId(bygCustom.getId())
                    .setUrl(data.getVideoCoverUrl()).setType(MyEnum.CUSTOM_DATA_COVER.getValue()));
        if (StringUtils.isNotBlank(data.getVideoUrl()))
            customDatas.add(new BygCustomData().setCId(bygCustom.getId())
                    .setUrl(data.getVideoUrl()).setType(MyEnum.CUSTOM_DATA_VIDEO.getValue()));
        if (customDatas.size() > 0 && ! bygCustomDataService.saveBatch(customDatas))
            return new BaseResDto<>(Status.ERROR, "保存风俗信息资料失败");
        return new BaseResDto<>(Status.SUCCESS);
    }

    @Override
    @Transactional
    public BaseResDto editCustomNo(Integer unitId, Integer customId, Boolean toUp) {
        BygCustom custom = getById(customId);
        LambdaQueryWrapper<BygCustom> wrapper = Wrappers
                .lambdaQuery(BygCustom.class).eq(BygCustom::getUnitId, unitId).last("LIMIT 1");
        Integer customNo = custom.getNo();
        if (BooleanUtils.isTrue(toUp)) wrapper.gt(BygCustom::getNo, customNo).orderByAsc(BygCustom::getNo);
        if (BooleanUtils.isFalse(toUp)) wrapper.lt(BygCustom::getNo, customNo).orderByDesc(BygCustom::getNo);
        BygCustom toCustom = getOne(wrapper);
        if (toCustom == null) return new BaseResDto(Status.SUCCESS);
        Integer temp = customNo;
        custom.setNo(toCustom.getNo());
        toCustom.setNo(temp);
        if (! updateBatchById(Arrays.asList(custom, toCustom))) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    @Transactional
    public BaseResDto delCustom(Integer customId) {
        if (! removeById(customId)) return new BaseResDto(Status.ERROR);
        LambdaQueryWrapper<BygCustomData> wrapper = Wrappers
                .lambdaQuery(BygCustomData.class).eq(BygCustomData::getCId, customId);
        if (! bygCustomDataService.remove(wrapper)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

}
